<?php

/**
 * @version     0.0.1
 * @package     com_cypher
 * @copyright   Copyright (C) 2013. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 * @author      Andrey J Bezpalov <abezpalov@ya.ru> - http://anodos.ru
 */
defined('_JEXEC') or die;

// Подключаем библиотеки
jimport('joomla.application.component.modellist');
jimport('joomla.filesystem.file');
jimport('joomla.filesystem.folder');

class CypherModelFile extends JModelList {

	/**
	 * Constructor.
	 *
	 * @param    array    An optional associative array of configuration settings.
	 * @see        JController
	 * @since    1.6
	 */
	public function __construct($config = array()) {
		parent::__construct($config);
	}

	public function upload($name, $alias, $option, $view, $itemId) {

		// Проверяем полномочия
		$user = JFactory::getUser();
		if (true != $user->authorise('core.edit')) {
			echo 'Функция только для авторизованных альфа-тестеров.';
			return false;
		}

		// Проверяем, все ли данные для добавления у нас есть
		if (true != $option and $view and $itemId) {
			echo 'Не возможно идентифицировать страницу сайта для привязки.';
			return false;
		} elseif (true != $name and $alias) {
			echo 'Не указано имя или псевдоним.';
			return false;
		}

		// Создаем "корневую папку для загрузок"
		$dir = JFactory::getApplication()->getCfg('tmp_path').'/'.'cypher'.'/';
		if (true != JFolder::exists($dir)) {
			// Создаем папку и файл index.html в ней
			JFolder::create($dir);
//			$f = fopen($dir.'index.html', "w");
//			fclose($f);
		}

		// Создаем временную папку для загрузки
		$dir = $dir.md5(time().rand()).'/';
		if (true != JFolder::exists($dir)) {
			JFolder::create($dir);
		}

		// Загружаем файл во временную папку
		$file = $dir.basename($_FILES['file']['name']);
		if (true != move_uploaded_file($_FILES['file']['tmp_name'], $file)) {
			return false;
		}

		// Определяем тип файла;
		if (true != $fileType = $this->onFileType($file)) {
			echo 'Неподдерживаемый тип файла.';
			return false;
		}

		if (true != $articleAlias = $this->onArticleAlias($option, $view, $itemId)) {
			echo 'Не удалось определить тип страницы сайта.';
			return false;
		}

		if (true != $dest = $this->onDest($fileType, $articleAlias)) {
			echo 'Не удалось определить папку для загрузки.';
			return false;
		}

		if (true != $src = $this->onSrc($fileType, $articleAlias, JFile::getName($file))) {
			echo 'Не удалось определить url полученного изображения.';
			return false;
		}

		// На осовании имени файла перемещаем его куда надо
		if ('doc' == $fileType) { // Перемещаем документа
			JFile::copy($file, $dest.JFile::getName($file));
			JFile::delete($file);
			JFolder::delete($dir);
		} elseif ('img' == $fileType) { // Копируем изображения

			// Создаем мегапиксельное изображение
			if (true != $this->resizeImageLovingly($file, $dest, 'm', 1000000)) {
				return false;
			}

			// Создаем превью изображения
			if (true != $this->resizeImageWildly($file, $dest, 's', 300, 220)) {
				return false;
			}

			// Копирует оригинал и чистит за собой
			JFile::copy($file, $dest.JFile::getName($file));
			JFile::delete($file);
			JFolder::delete($dir);

		} else {
			echo 'Неизвестный тип документа.';
			JFile::delete($file);
			JFolder::delete($dir);
			return false;
		}

		// Обновляем имя файла
		$file = $dest.JFile::getName($file);

		// Проверяем есть ли уже привязка к файлу
		$fileLinkId = $this->getFileLinkId($option, $view, $itemId, $src);
		if (true != $fileLinkId) { // Нет привязки в базе
			$fileLinkId = $this->addFileLink($name, $alias, $option, $view, $itemId, $src, $fileType);
			if (true != $fileLinkId) { // Нет привязки в базе
				echo 'Не удалось привязать файл в базе.';
				return false;
			} else { // Есть привязка в базе
				echo 'Загрузка '.basename($file). ' завершена.';
				return true;
			}
		} else { // Есть привязка в базе
			$this->updateFileLink($fileLinkId, $name, $alias);
			echo 'Обновление '.basename($file). ' завершено.';
		}
	}

	// Определяем типа файла
	protected function onFileType($file) {
		$ext = JFile::getExt($file);
		switch ($ext) {
			case 'jpg' : return 'img';
			case 'png' : return 'img';
			case 'pdf' : return 'doc';
			case 'mwb' : return 'doc';
			default : return false;
		}
	}

	// Определяем псевдоним статьи
	protected function onArticleAlias($option, $view, $itemId) {

		// Если страница статьи
		if (('com_content' == $option) and ('article' == $view) and (true == $itemId)) {

			// Подключаемся к базе
			$db = JFactory::getDBO();

			// Выполняем запрос
			$query = "
				SELECT alias
				FROM #__content
				WHERE #__content.id = '{$itemId}';";
			$db->setQuery($query);
			$artcleAlias = $db->loadResult();

			// Возвращаем результат
			return $artcleAlias;

		} else { // Что-то еще
			return false;
		}
	}

	// Определяем папку-назначение файла (при необходимости, создаем)
	protected function onDest($fileType, $articleAlias) {

		// Определяем переменные
		$dest = JPATH_SITE.'/'.$fileType.'s/';

		// Прилепляем псевдоним статьи
		$subDirs = explode('-', $articleAlias);
		for ($i=0; $i<sizeof($subDirs); $i++) {
			$dest .= $subDirs[$i].'/';
		}

		// Создаем папку если ее нет
		if (true != JFolder::exists($dest)) {
			// Создаем папку и файл index.html в ней
			JFolder::create($dest);
			// TODO Создаем пустой index.html
		}

		// Возвращаем результат
		return $dest;
	}

	protected function onSrc($fileType, $articleAlias, $fileName) {

		// Определяем переменные
		$src = '/'.$fileType.'s/';

		// Прилепляем псевдоним статьи
		$subDirs = explode('-', $articleAlias);
		for ($i=0; $i<sizeof($subDirs); $i++) {
			$src .= $subDirs[$i].'/';
		}

		// Добавляем имя файла
		$src .= $fileName;

		// Возвращаем результат
		return $src;
	}

	protected function getFileLinkId($option, $view, $itemId, $src) {

		// Подключаемся к базе
		$db = JFactory::getDBO();

		// Выполняем запрос
		$query = "
			SELECT id
			FROM `#__cypher_file`
			WHERE '{$option}' <=> #__cypher_file.option
			AND '{$view}' <=> #__cypher_file.view
			AND '{$itemId}' <=> #__cypher_file.item_id
			AND '{$src}' <=> #__cypher_file.src;";
		$db->setQuery($query);
		$id = $db->loadResult();

		// Возвращаем результат
		return $id;
	}

	protected function addFileLink($name, $alias, $option, $view, $itemId, $src, $type, $state = 1) {

		// Инициализируем переменные
		$db = JFactory::getDBO();
		$createdBy = JFactory::getUser()->id;
		$ordering = $this->getMaxOrdering($option, $view, $itemId)+1;

		// Выполняем запрос вставки
		$query = "
			INSERT INTO #__cypher_file (
				`name`,
				`alias`,
				`option`,
				`view`,
				`item_id`,
				`src`,
				`type`,
				`ordering`,
				`created`,
				`created_by`,
				`state`)
			VALUES (
				'{$name}',
				'{$alias}',
				'{$option}',
				'{$view}',
				'{$itemId}',
				'{$src}',
				'{$type}',
				'{$ordering}',
				NOW(),
				'{$createdBy}',
				'{$state}');";
		// echo $query.'<br/>';
		$db->setQuery($query);
		$db->query();

		// Выполняем запрос выборки
		$query = "
			SELECT id
			FROM `#__cypher_file`
			WHERE '{$option}' <=> #__cypher_file.option
			AND '{$view}' <=> #__cypher_file.view
			AND '{$itemId}' <=> #__cypher_file.item_id
			AND '{$src}' <=> #__cypher_file.src;";
		// echo $query.'<br/>';
		$db->setQuery($query);
		$id = $db->loadResult();

		// Возвращаем результат
		return $id;
	}

	protected function getMaxOrdering($option, $view, $itemId) {

		// Подключаемся к базе
		$db = JFactory::getDBO();

		// Выполняем запрос
		$query = "
			SELECT max(ordering)
			FROM `#__cypher_file`
			WHERE '{$option}' <=> #__cypher_file.option
			AND '{$view}' <=> #__cypher_file.view
			AND '{$itemId}' <=> #__cypher_file.item_id;";
		$db->setQuery($query);
		$ordering = $db->loadResult();

		// Возвращаем результат
		return $ordering;
	}

	// Добавляет привязку
	protected function updateFileLink($fileLinkId, $name, $alias, $state = 1) {

		// Подключаемся к базе
		$db = JFactory::getDBO();
		$modifiedBy = JFactory::getUser()->id;

		// Выполняем запрос вставки
		$query = "
			UPDATE #__cypher_file SET
				`name` = '{$name}',
				`alias` = '{$alias}',
				`modified` = NOW(),
				`modified_by` = '{$modifiedBy}',
				`state` = '{$state}'
			WHERE `id` <=> '{$fileLinkId}';";
		$db->setQuery($query);
		$db->query();

		// Выполняем запрос выборки
		$query = "
			SELECT id
			FROM `#__cypher_file`
			WHERE '{$fileLinkId}' <=> #__cypher_file.id
			AND '{$name}' <=> #__cypher_file.name
			AND '{$alias}' <=> #__cypher_file.alias;";
		// echo $query.'<br/>';
		$db->setQuery($query);
		$id = $db->loadResult();

		// Возвращаем результат
		return $id;
	}

	// Масштабирует изображение, отрезает лишнее
	protected function resizeImageWildly($sourceFile, $dest, $suffix, $newWidth, $newHeight) {

		// Получаем исходный размер картинки
		$originalSize = getimagesize($sourceFile);
		$originalWidth = $originalSize[0];
		$originalHeight = $originalSize[1];

		// Проверяем, не мало ли изображение
		if (($newWidth > $originalWidth) or ($newHeight > $originalHeight)) {
			echo 'Изображение слишком мало.';
			return false;
		}

		// Рассчитываем сколько отрезать и от куда отрезать
		$distortion = $originalWidth / $originalHeight - $newWidth / $newHeight;
		if (0 > $distortion) { // Режем по высоте
			$srcX = 0;
			$srcY = floor(($originalHeight - $originalWidth*$newHeight/$newWidth)/2);
			$srcWidth = $originalWidth;
			$srcHeight = ceil($originalHeight - 2*$srcY);
		} elseif (0 < $distortion) { // Режем по ширине
			$srcX = floor(($originalWidth - $originalHeight*$newWidth/$newHeight)/2);
			$srcY = 0;
			$srcWidth = ceil($originalWidth - 2*$srcX);
			$srcHeight = $originalHeight;
		} elseif (0 == $distortion) { // Задаем нулевые значения "отрезания"
			$srcX = 0;
			$srcY = 0;
			$srcWidth = $originalWidth;
			$srcHeight = $originalHeight;
		} else { // Что-то пошло не так
			echo "Опять разделили на ноль :(";
			return false;
		}

		// Открываем изображение
		$ext = JFile::getExt($sourceFile);
		switch ($ext) {
			case 'jpg' : $originalImage = imagecreatefromjpeg($sourceFile); break;
			case 'png' : $originalImage = imagecreatefrompng($sourceFile); break;
			default : return false;
		}

		// Создаем новое изображение
		$newImage = imagecreatetruecolor($newWidth, $newHeight);

		// Масштабируем изображение
		imagecopyresampled($newImage, $originalImage, 0, 0, $srcX, floor($srcY/3), $newWidth, $newHeight, $srcWidth, $srcHeight);

		// Сохраняем в файл
		imagejpeg($newImage, $dest.JFile::getName(JFile::stripExt($sourceFile)).'-'.$suffix.'.'.JFile::getExt($sourceFile));

		return true;
	}

	// Масштабирует изображение, без отрезания
	protected function resizeImageLovingly($sourceFile, $dest, $suffix, $size) {

		// Получаем исходный размер картинки
		$originalSize = getimagesize($sourceFile);
		$originalWidth = $originalSize[0];
		$originalHeight = $originalSize[1];

		// Проверяем, не мало ли изображение
		if ($originalWidth*$originalHeight <= $size) {
			// Масштабирование не нужно. Просто копируем и говорим, что все отлично.
			JFile::copy($sourceFile, $dest.JFile::getName(JFile::stripExt($sourceFile)).'-'.$suffix.'.'.JFile::getExt($sourceFile));
			return true;
		} else {
			$newWidth = round(sqrt($size*$originalWidth/$originalHeight));
			$newHeight = round(sqrt($size*$originalHeight/$originalWidth));
		}


		// Открываем изображение
		$ext = JFile::getExt($sourceFile);
		switch ($ext) {
			case 'jpg' : $originalImage = imagecreatefromjpeg($sourceFile); break;
			case 'png' : $originalImage = imagecreatefrompng($sourceFile); break;
			default : return false;
		}

		// Создаем новое изображение
		$newImage = imagecreatetruecolor($newWidth, $newHeight);

		// Масштабируем изображение
		imagecopyresampled($newImage, $originalImage, 0, 0, 0, 0, $newWidth, $newHeight, $originalWidth, $originalHeight);

		// Сохраняем в файл
		imagejpeg($newImage, $dest.JFile::getName(JFile::stripExt($sourceFile)).'-'.$suffix.'.'.JFile::getExt($sourceFile));

		return true;
	}
}
